From 0b9d367cf8677be6d54c6d80e393499c99398d2f Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Sun, 14 Mar 2004 18:23:01 +0000 Subject: [PATCH] bitkeeper revision 1.795 (4054a3055ggg3MJTpSU1-ZFQRfQQ5g) xend.py, setup.py: new file Many files: Rewritten the Xen control daemon in Python, with C extensions for the low-level bits. All our Python libraries now throw exceptions on error rather than returning error codes --- this will require our higher-level scripts to be updated at some point. --- .rootkeys | 2 + tools/examples/xc_dom_create.py | 11 +- tools/xc/py/Makefile | 2 +- tools/xc/py/Xc.c | 510 +++---- tools/xc/py/XenoUtil.py | 23 +- tools/xend/Makefile | 31 +- tools/xend/setup.py | 11 + tools/xend/xend.py | 454 ++++++ tools/xend/xend_utils.c | 1322 +++++++++++------ tools/xentrace/Makefile | 20 +- .../arch/xeno/drivers/console/console.c | 16 +- .../include/asm-xeno/control_if.h | 14 +- 12 files changed, 1600 insertions(+), 816 deletions(-) create mode 100644 tools/xend/setup.py create mode 100755 tools/xend/xend.py diff --git a/.rootkeys b/.rootkeys index e078d7cc52..c090dc8fd4 100644 --- a/.rootkeys +++ b/.rootkeys @@ -89,6 +89,8 @@ 3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xc/py/XenoUtil.py 3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py 40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend/Makefile +4054a2fdkdATEnRw-U7AUlgu-6JiUA tools/xend/setup.py +4054a301VEag2GwrBrFBna5U1BGlLA tools/xend/xend.py 40431ac8wrUEj-XM7B8smFtx_HA7lQ tools/xend/xend_utils.c 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8 diff --git a/tools/examples/xc_dom_create.py b/tools/examples/xc_dom_create.py index 4af0d9b0da..94f37a4494 100755 --- a/tools/examples/xc_dom_create.py +++ b/tools/examples/xc_dom_create.py @@ -237,9 +237,14 @@ def make_domain(): xc.domain_destroy ( dom=id ) sys.exit() - ports = xc.evtchn_open( dom2=id ) - if not ports: + cmsg = 'new_control_interface(dom='+str(id)+')' + xend_response = XenoUtil.xend_control_message(cmsg) + if not xend_response['success']: print "Error creating initial event channel" + print "Error type: " + xend_response['error_type'] + if xend_response['error_type'] == 'exception': + print "Exception type: " + xend_response['exception_type'] + print "Exception value: " + xend_response['exception_value'] xc.domain_destroy ( dom=id ) sys.exit() @@ -292,7 +297,7 @@ def make_domain(): xc.domain_destroy ( dom=id ) sys.exit() - return (id, 9600+ports['port1']) + return (id, xend_response['console_port']) # end of make_domain() def mkpidfile(): diff --git a/tools/xc/py/Makefile b/tools/xc/py/Makefile index 058450e0dc..9f66e3c05e 100644 --- a/tools/xc/py/Makefile +++ b/tools/xc/py/Makefile @@ -1,5 +1,5 @@ -all: ../lib/libxc.so.1.3.0 ../lib/xc.h +all: python setup.py build install: all diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c index 3515047ee9..124942bbb0 100644 --- a/tools/xc/py/Xc.c +++ b/tools/xc/py/Xc.c @@ -1,19 +1,13 @@ /****************************************************************************** * Xc.c * - * Copyright (c) 2003, K A Fraser + * Copyright (c) 2003-2004, K A Fraser (University of Cambridge) */ #include #include -#if 1 -#define DPRINTF(_f, _a...) \ - fprintf(stderr, "%s:%s:%d:: " _f "\n" , \ - __FILE__ , __FUNCTION__ , __LINE__ , ## _a) -#else -#define DPRINTF(_f, _a...) ((void)0) -#endif +static PyObject *xc_error, *zero; typedef struct { PyObject_HEAD; @@ -39,13 +33,10 @@ static PyObject *pyxc_domain_create(PyObject *self, if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|is", kwd_list, &mem_kb, &name) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, &dom)) < 0 ) - return PyLong_FromLong(ret); + return PyErr_SetFromErrno(xc_error); return PyLong_FromUnsignedLongLong(dom); } @@ -57,19 +48,17 @@ static PyObject *pyxc_domain_start(PyObject *self, XcObject *xc = (XcObject *)self; u64 dom; - int ret; static char *kwd_list[] = { "dom", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &dom) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_domain_start(xc->xc_handle, dom); + if ( xc_domain_start(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_domain_stop(PyObject *self, @@ -79,19 +68,17 @@ static PyObject *pyxc_domain_stop(PyObject *self, XcObject *xc = (XcObject *)self; u64 dom; - int ret; static char *kwd_list[] = { "dom", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &dom) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_domain_stop(xc->xc_handle, dom); + if ( xc_domain_stop(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_domain_destroy(PyObject *self, @@ -101,20 +88,19 @@ static PyObject *pyxc_domain_destroy(PyObject *self, XcObject *xc = (XcObject *)self; u64 dom; - int force = 0, ret; + int force = 0; static char *kwd_list[] = { "dom", "force", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwd_list, &dom, &force) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_domain_destroy(xc->xc_handle, dom, force); + if ( xc_domain_destroy(xc->xc_handle, dom, force) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_domain_pincpu(PyObject *self, @@ -124,20 +110,19 @@ static PyObject *pyxc_domain_pincpu(PyObject *self, XcObject *xc = (XcObject *)self; u64 dom; - int cpu = -1, ret; + int cpu = -1; static char *kwd_list[] = { "dom", "cpu", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwd_list, &dom, &cpu) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_domain_pincpu(xc->xc_handle, dom, cpu); + if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_domain_getinfo(PyObject *self, @@ -155,20 +140,12 @@ static PyObject *pyxc_domain_getinfo(PyObject *self, if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|Li", kwd_list, &first_dom, &max_doms) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL ) - { - DPRINTF("out of memory."); - nr_doms = 0; - } - else - { - nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info); - } + return PyErr_NoMemory(); + + nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info); list = PyList_New(nr_doms); for ( i = 0 ; i < nr_doms; i++ ) @@ -185,8 +162,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self, "name", info[i].name)); } - if ( info != NULL ) - free(info); + free(info); return list; } @@ -199,20 +175,19 @@ static PyObject *pyxc_linux_save(PyObject *self, u64 dom; char *state_file; - int progress = 1, ret; + int progress = 1; static char *kwd_list[] = { "dom", "state_file", "progress", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|i", kwd_list, &dom, &state_file, &progress) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_linux_save(xc->xc_handle, dom, state_file, progress); + if ( xc_linux_save(xc->xc_handle, dom, state_file, progress) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_linux_restore(PyObject *self, @@ -222,21 +197,17 @@ static PyObject *pyxc_linux_restore(PyObject *self, XcObject *xc = (XcObject *)self; char *state_file; - int progress = 1, ret; + int progress = 1; u64 dom; static char *kwd_list[] = { "state_file", "progress", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwd_list, &state_file, &progress) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_linux_restore(xc->xc_handle, state_file, progress, &dom); - if ( ret < 0 ) - return PyLong_FromLong(ret); + if ( xc_linux_restore(xc->xc_handle, state_file, progress, &dom) != 0 ) + return PyErr_SetFromErrno(xc_error); return PyLong_FromUnsignedLongLong(dom); } @@ -249,20 +220,18 @@ static PyObject *pyxc_linux_build(PyObject *self, u64 dom; char *image, *ramdisk = NULL, *cmdline = ""; - int ret; static char *kwd_list[] = { "dom", "image", "ramdisk", "cmdline", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|ss", kwd_list, &dom, &image, &ramdisk, &cmdline) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_linux_build(xc->xc_handle, dom, image, ramdisk, cmdline); + if ( xc_linux_build(xc->xc_handle, dom, image, ramdisk, cmdline) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_netbsd_build(PyObject *self, @@ -273,20 +242,18 @@ static PyObject *pyxc_netbsd_build(PyObject *self, u64 dom; char *image, *ramdisk = NULL, *cmdline = ""; - int ret; static char *kwd_list[] = { "dom", "image", "ramdisk", "cmdline", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|ss", kwd_list, &dom, &image, &ramdisk, &cmdline) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_netbsd_build(xc->xc_handle, dom, image, cmdline); + if ( xc_netbsd_build(xc->xc_handle, dom, image, cmdline) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_bvtsched_global_set(PyObject *self, @@ -296,19 +263,17 @@ static PyObject *pyxc_bvtsched_global_set(PyObject *self, XcObject *xc = (XcObject *)self; unsigned long ctx_allow; - int ret; static char *kwd_list[] = { "ctx_allow", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_bvtsched_global_set(xc->xc_handle, ctx_allow); + if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_bvtsched_domain_set(PyObject *self, @@ -319,22 +284,20 @@ static PyObject *pyxc_bvtsched_domain_set(PyObject *self, u64 dom; unsigned long mcuadv, warp, warpl, warpu; - int ret; static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", "warpu", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Lllll", kwd_list, &dom, &mcuadv, &warp, &warpl, &warpu) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, - warp, warpl, warpu); + if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, + warp, warpl, warpu) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_vif_scheduler_set(PyObject *self, @@ -346,7 +309,6 @@ static PyObject *pyxc_vif_scheduler_set(PyObject *self, u64 dom; unsigned int vif; xc_vif_sched_params_t sched = { 0, 0 }; - int ret; static char *kwd_list[] = { "dom", "vif", "credit_bytes", "credit_usecs", NULL }; @@ -355,14 +317,13 @@ static PyObject *pyxc_vif_scheduler_set(PyObject *self, &dom, &vif, &sched.credit_bytes, &sched.credit_usec) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vif_scheduler_set(xc->xc_handle, dom, vif, &sched); + if ( xc_vif_scheduler_set(xc->xc_handle, dom, vif, &sched) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_vif_scheduler_get(PyObject *self, @@ -370,32 +331,23 @@ static PyObject *pyxc_vif_scheduler_get(PyObject *self, PyObject *kwds) { XcObject *xc = (XcObject *)self; - PyObject *dict; u64 dom; unsigned int vif; xc_vif_sched_params_t sched; - int ret; static char *kwd_list[] = { "dom", "vif", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, &dom, &vif) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vif_scheduler_get(xc->xc_handle, dom, vif, &sched); + if ( xc_vif_scheduler_get(xc->xc_handle, dom, vif, &sched) != 0 ) + return PyErr_SetFromErrno(xc_error); - if ( ret < 0 ) - dict = Py_BuildValue("{}"); - else - dict = Py_BuildValue("{s:l,s:l}", - "credit_bytes", sched.credit_bytes, - "credit_usecs", sched.credit_usec); - - return dict; + return Py_BuildValue("{s:l,s:l}", + "credit_bytes", sched.credit_bytes, + "credit_usecs", sched.credit_usec); } static PyObject *pyxc_vif_stats_get(PyObject *self, @@ -403,34 +355,25 @@ static PyObject *pyxc_vif_stats_get(PyObject *self, PyObject *kwds) { XcObject *xc = (XcObject *)self; - PyObject *dict; u64 dom; unsigned int vif; xc_vif_stats_t stats; - int ret; static char *kwd_list[] = { "dom", "vif", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, &dom, &vif) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vif_stats_get(xc->xc_handle, dom, vif, &stats); + if ( xc_vif_stats_get(xc->xc_handle, dom, vif, &stats) != 0 ) + return PyErr_SetFromErrno(xc_error); - if ( ret < 0 ) - dict = Py_BuildValue("{}"); - else - dict = Py_BuildValue("{s:L,s:L,s:L,s:L}", - "tx_bytes", stats.tx_bytes, - "tx_packets", stats.tx_pkts, - "rx_bytes", stats.rx_bytes, - "rx_packets", stats.rx_pkts); - - return dict; + return Py_BuildValue("{s:L,s:L,s:L,s:L}", + "tx_bytes", stats.tx_bytes, + "tx_packets", stats.tx_pkts, + "rx_bytes", stats.rx_bytes, + "rx_packets", stats.rx_pkts); } static PyObject *pyxc_vbd_create(PyObject *self, @@ -441,20 +384,19 @@ static PyObject *pyxc_vbd_create(PyObject *self, u64 dom; unsigned int vbd; - int writeable, ret; + int writeable; static char *kwd_list[] = { "dom", "vbd", "writeable", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Lii", kwd_list, &dom, &vbd, &writeable) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vbd_create(xc->xc_handle, dom, vbd, writeable); - - return PyInt_FromLong(ret); + if ( xc_vbd_create(xc->xc_handle, dom, vbd, writeable) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; } static PyObject *pyxc_vbd_destroy(PyObject *self, @@ -465,20 +407,18 @@ static PyObject *pyxc_vbd_destroy(PyObject *self, u64 dom; unsigned int vbd; - int ret; static char *kwd_list[] = { "dom", "vbd", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, &dom, &vbd) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vbd_destroy(xc->xc_handle, dom, vbd); - - return PyInt_FromLong(ret); + if ( xc_vbd_destroy(xc->xc_handle, dom, vbd) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; } static PyObject *pyxc_vbd_grow(PyObject *self, @@ -490,7 +430,6 @@ static PyObject *pyxc_vbd_grow(PyObject *self, u64 dom; unsigned int vbd; xc_vbdextent_t extent; - int ret; static char *kwd_list[] = { "dom", "vbd", "device", "start_sector", "nr_sectors", NULL }; @@ -500,14 +439,13 @@ static PyObject *pyxc_vbd_grow(PyObject *self, &extent.real_device, &extent.start_sector, &extent.nr_sectors) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vbd_grow(xc->xc_handle, dom, vbd, &extent); - - return PyInt_FromLong(ret); + if ( xc_vbd_grow(xc->xc_handle, dom, vbd, &extent) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; } static PyObject *pyxc_vbd_shrink(PyObject *self, @@ -518,20 +456,18 @@ static PyObject *pyxc_vbd_shrink(PyObject *self, u64 dom; unsigned int vbd; - int ret; static char *kwd_list[] = { "dom", "vbd", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, &dom, &vbd) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_vbd_shrink(xc->xc_handle, dom, vbd); - - return PyInt_FromLong(ret); + if ( xc_vbd_shrink(xc->xc_handle, dom, vbd) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; } static PyObject *pyxc_vbd_setextents(PyObject *self, @@ -544,44 +480,38 @@ static PyObject *pyxc_vbd_setextents(PyObject *self, u64 dom; unsigned int vbd; xc_vbdextent_t *extents = NULL; - int ret, i, nr_extents; + int i, nr_extents; static char *kwd_list[] = { "dom", "vbd", "extents", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "LiO", kwd_list, &dom, &vbd, &list) ) - { - DPRINTF("could not parse parameter list."); - goto fail; - } + return NULL; - if ( (nr_extents = PyList_Size(list)) < 0 ) + if ( !PyList_Check(list) ) { - DPRINTF("parameter 'extents' is not a list."); - goto fail; + PyErr_SetString(PyExc_TypeError, "parameter 'extents' is not a list"); + return NULL; } - if ( nr_extents != 0 ) + if ( (nr_extents = PyList_Size(list)) != 0 ) { - extents = malloc(nr_extents * sizeof(xc_vbdextent_t)); - if ( extents == NULL ) - { - DPRINTF("out of memory."); - goto fail; - } + if ( (extents = malloc(nr_extents * sizeof(xc_vbdextent_t))) == NULL ) + return PyErr_NoMemory(); for ( i = 0; i < nr_extents; i++ ) { dict = PyList_GetItem(list, i); if ( !PyDict_Check(dict) ) { - DPRINTF("extent %d -- extent is not a dictionary.", i); + PyErr_SetString(PyExc_TypeError, "extent is not a dictionary"); goto fail; } if ( (obj = PyDict_GetItemString(dict, "device")) == NULL ) { - DPRINTF("extent %d -- 'device' is not in the dictionary.", i); + PyErr_SetString(PyExc_TypeError, + "'device' is not in the dictionary"); goto fail; } if ( PyInt_Check(obj) ) @@ -594,14 +524,15 @@ static PyObject *pyxc_vbd_setextents(PyObject *self, } else { - DPRINTF("extent %d -- 'device' is not an int or long.", i); + PyErr_SetString(PyExc_TypeError, + "'device' is not an int or long"); goto fail; } if ( (obj = PyDict_GetItemString(dict, "start_sector")) == NULL ) { - DPRINTF("extent %d -- 'start_sector' is not " - "in the dictionary.", i); + PyErr_SetString(PyExc_TypeError, + "'start_sector' is not in the dictionary"); goto fail; } if ( PyInt_Check(obj) ) @@ -614,15 +545,15 @@ static PyObject *pyxc_vbd_setextents(PyObject *self, } else { - DPRINTF("extent %d -- 'start_sector' is not " - "an int or long.", i); + PyErr_SetString(PyExc_TypeError, + "'start_sector' is not an int or long"); goto fail; } if ( (obj = PyDict_GetItemString(dict, "nr_sectors")) == NULL ) { - DPRINTF("extent %d -- 'nr_sectors' is not " - "in the dictionary.", i); + PyErr_SetString(PyExc_TypeError, + "'nr_sectors' is not in the dictionary"); goto fail; } if ( PyInt_Check(obj) ) @@ -635,19 +566,24 @@ static PyObject *pyxc_vbd_setextents(PyObject *self, } else { - DPRINTF("extent %d -- 'nr_sectors' is not " - "an int or long.", i); + PyErr_SetString(PyExc_TypeError, + "'nr_sectors' is not an int or long"); goto fail; } } } - ret = xc_vbd_setextents(xc->xc_handle, dom, vbd, nr_extents, extents); - + if ( xc_vbd_setextents(xc->xc_handle, dom, vbd, nr_extents, extents) != 0 ) + { + PyErr_SetFromErrno(xc_error); + goto fail; + } + if ( extents != NULL ) free(extents); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; fail: if ( extents != NULL ) @@ -666,51 +602,38 @@ static PyObject *pyxc_vbd_getextents(PyObject *self, u64 dom; unsigned int vbd; xc_vbdextent_t *extents; - int i, nr_extents, max_extents; + int i, nr_extents; static char *kwd_list[] = { "dom", "vbd", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, &dom, &vbd) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - extents = malloc(MAX_EXTENTS * sizeof(xc_vbdextent_t)); - if ( extents == NULL ) - { - DPRINTF("out of memory."); - max_extents = 0; - } - else - { - max_extents = MAX_EXTENTS; - } + if ( (extents = malloc(MAX_EXTENTS * sizeof(xc_vbdextent_t))) == NULL ) + return PyErr_NoMemory(); - nr_extents = xc_vbd_getextents(xc->xc_handle, dom, vbd, max_extents, + nr_extents = xc_vbd_getextents(xc->xc_handle, dom, vbd, MAX_EXTENTS, extents, NULL); - if ( nr_extents <= 0 ) + if ( nr_extents < 0 ) { - list = PyList_New(0); + free(extents); + return PyErr_SetFromErrno(xc_error); } - else + + list = PyList_New(nr_extents); + for ( i = 0; i < nr_extents; i++ ) { - list = PyList_New(nr_extents); - for ( i = 0; i < nr_extents; i++ ) - { - PyList_SetItem( - list, i, - Py_BuildValue("{s:i,s:L,s:L}", - "device", extents[i].real_device, - "start_sector", extents[i].start_sector, - "nr_sectors", extents[i].nr_sectors)); - } + PyList_SetItem( + list, i, + Py_BuildValue("{s:i,s:L,s:L}", + "device", extents[i].real_device, + "start_sector", extents[i].start_sector, + "nr_sectors", extents[i].nr_sectors)); } - if ( extents != NULL ) - free(extents); + free(extents); return list; } @@ -731,20 +654,15 @@ static PyObject *pyxc_vbd_probe(PyObject *self, if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|Li", kwd_list, &dom, &max_vbds) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - info = malloc(max_vbds * sizeof(xc_vbd_t)); - if ( info == NULL ) - { - DPRINTF("out of memory."); - nr_vbds = 0; - } - else + if ( (info = malloc(max_vbds * sizeof(xc_vbd_t))) == NULL ) + return PyErr_NoMemory(); + + if ( (nr_vbds = xc_vbd_probe(xc->xc_handle, dom, max_vbds, info)) < 0 ) { - nr_vbds = xc_vbd_probe(xc->xc_handle, dom, max_vbds, info); + free(info); + return PyErr_SetFromErrno(xc_error); } list = PyList_New(nr_vbds); @@ -759,8 +677,7 @@ static PyObject *pyxc_vbd_probe(PyObject *self, "nr_sectors", info[i].nr_sectors)); } - if ( info != NULL ) - free(info); + free(info); return list; } @@ -770,30 +687,22 @@ static PyObject *pyxc_evtchn_open(PyObject *self, PyObject *kwds) { XcObject *xc = (XcObject *)self; - PyObject *dict; u64 dom1 = DOMID_SELF, dom2 = DOMID_SELF; - int port1, port2, ret; + int port1, port2; static char *kwd_list[] = { "dom1", "dom2", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|LL", kwd_list, &dom1, &dom2) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_evtchn_open(xc->xc_handle, dom1, dom2, &port1, &port2); + if ( xc_evtchn_open(xc->xc_handle, dom1, dom2, &port1, &port2) != 0 ) + return PyErr_SetFromErrno(xc_error); - if ( ret < 0 ) - dict = Py_BuildValue("{}"); - else - dict = Py_BuildValue("{s:i,s:i}", - "port1", port1, - "port2", port2); - - return dict; + return Py_BuildValue("{s:i,s:i}", + "port1", port1, + "port2", port2); } static PyObject *pyxc_evtchn_close(PyObject *self, @@ -803,20 +712,19 @@ static PyObject *pyxc_evtchn_close(PyObject *self, XcObject *xc = (XcObject *)self; u64 dom = DOMID_SELF; - int port, ret; + int port; static char *kwd_list[] = { "port", "dom", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|L", kwd_list, &port, &dom) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_evtchn_close(xc->xc_handle, dom, port); + if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_evtchn_send(PyObject *self, @@ -825,19 +733,18 @@ static PyObject *pyxc_evtchn_send(PyObject *self, { XcObject *xc = (XcObject *)self; - int port, ret; + int port; static char *kwd_list[] = { "port", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } - ret = xc_evtchn_send(xc->xc_handle, port); + if ( xc_evtchn_send(xc->xc_handle, port) != 0 ) + return PyErr_SetFromErrno(xc_error); - return PyInt_FromLong(ret); + Py_INCREF(zero); + return zero; } static PyObject *pyxc_evtchn_status(PyObject *self, @@ -854,39 +761,31 @@ static PyObject *pyxc_evtchn_status(PyObject *self, if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|L", kwd_list, &port1, &dom1) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } ret = xc_evtchn_status(xc->xc_handle, dom1, port1, &dom2, &port2, &status); + if ( ret != 0 ) + return PyErr_SetFromErrno(xc_error); - if ( ret < 0 ) + switch ( status ) { + case EVTCHNSTAT_closed: + dict = Py_BuildValue("{s:s}", + "status", "closed"); + break; + case EVTCHNSTAT_disconnected: + dict = Py_BuildValue("{s:s}", + "status", "disconnected"); + break; + case EVTCHNSTAT_connected: + dict = Py_BuildValue("{s:s,s:L,s:i}", + "status", "connected", + "dom", dom2, + "port", port2); + break; + default: dict = Py_BuildValue("{}"); - } - else - { - switch ( status ) - { - case EVTCHNSTAT_closed: - dict = Py_BuildValue("{s:s}", - "status", "closed"); - break; - case EVTCHNSTAT_disconnected: - dict = Py_BuildValue("{s:s}", - "status", "disconnected"); - break; - case EVTCHNSTAT_connected: - dict = Py_BuildValue("{s:s,s:L,s:i}", - "status", "connected", - "dom", dom2, - "port", port2); - break; - default: - dict = Py_BuildValue("{}"); - break; - } + break; } return dict; @@ -904,15 +803,15 @@ static PyObject *pyxc_physdev_pci_access_modify(PyObject *self, if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Liiii", kwd_list, &dom, &bus, &dev, &func, &enable) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } ret = xc_physdev_pci_access_modify( xc->xc_handle, dom, bus, dev, func, enable); - - return PyInt_FromLong(ret); + if ( ret != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; } static PyObject *pyxc_readconsolering(PyObject *self, @@ -928,14 +827,13 @@ static PyObject *pyxc_readconsolering(PyObject *self, static char *kwd_list[] = { "clear", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) ) - { - DPRINTF("could not parse parameter list."); return NULL; - } ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear); + if ( ret < 0 ) + return PyErr_SetFromErrno(xc_error); - return PyString_FromStringAndSize(str, (ret < 0) ? 0 : ret); + return PyString_FromStringAndSize(str, ret); } static PyObject *pyxc_physinfo(PyObject *self, @@ -943,26 +841,20 @@ static PyObject *pyxc_physinfo(PyObject *self, PyObject *kwds) { XcObject *xc = (XcObject *)self; - PyObject *ret_obj; - int xc_ret; xc_physinfo_t info; - if ( (xc_ret = xc_physinfo(xc->xc_handle, &info)) == 0 ) - { - ret_obj = Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}", - "ht_per_core", info.ht_per_core, - "cores", info.cores, - "total_pages", info.total_pages, - "free_pages", info.free_pages, - "cpu_khz", info.cpu_khz); - } - else - { - Py_INCREF(Py_None); - ret_obj = Py_None; - } - - return ret_obj; + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_physinfo(xc->xc_handle, &info) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}", + "ht_per_core", info.ht_per_core, + "cores", info.cores, + "total_pages", info.total_pages, + "free_pages", info.free_pages, + "cpu_khz", info.cpu_khz); } static PyMethodDef pyxc_methods[] = { @@ -1305,7 +1197,15 @@ static PyMethodDef PyXc_methods[] = { { NULL, NULL, 0, NULL } }; -DL_EXPORT(void) initXc(void) +PyMODINIT_FUNC initXc(void) { - Py_InitModule("Xc", PyXc_methods); + PyObject *m, *d; + + m = Py_InitModule("Xc", PyXc_methods); + + d = PyModule_GetDict(m); + xc_error = PyErr_NewException("Xc.error", NULL, NULL); + PyDict_SetItemString(d, "error", xc_error); + + zero = PyInt_FromLong(0); } diff --git a/tools/xc/py/XenoUtil.py b/tools/xc/py/XenoUtil.py index 27b6fbb390..520f585062 100644 --- a/tools/xc/py/XenoUtil.py +++ b/tools/xc/py/XenoUtil.py @@ -1,4 +1,4 @@ -import string, re, os, sys +import os, re, socket, string, sys, tempfile ##### Module variables @@ -184,6 +184,27 @@ def lookup_disk_uname( uname ): return segments +##### Management of the Xen control daemon +##### (c) Keir Fraser, University of Cambridge + +def xend_control_message( message ): + """Takes a textual control message and sends it to the 'xend' Xen + control daemon. Returns a dictionary containing the daemon's multi-part + response.""" + tmpdir = tempfile.mkdtemp() + try: + ctl = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + ctl.bind(tmpdir+'/sock') + ctl.sendto(message, '/var/run/xend/management_sock') + data, addr = ctl.recvfrom(2048) + ctl.close() + finally: + if os.path.exists(tmpdir+'/sock'): + os.unlink(tmpdir+'/sock') + if os.path.exists(tmpdir): + os.rmdir(tmpdir) + return eval(data) + ##### VD Management-related functions diff --git a/tools/xend/Makefile b/tools/xend/Makefile index 619f980975..de6aeb3982 100644 --- a/tools/xend/Makefile +++ b/tools/xend/Makefile @@ -1,27 +1,24 @@ -CC = gcc -CFLAGS = -Wall -O3 -CFLAGS += -I../xc/lib -I../../xenolinux-sparse/include - -HDRS = $(wildcard *.h) -OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) - -BIN = xend - -all: $(BIN) +all: + python setup.py build install: all - mkdir -p $(prefix)/usr/sbin - cp $(BIN) $(prefix)/usr/sbin - chmod 755 $(prefix)/usr/sbin/$(BIN) + if [ "$(prefix)" = "" ]; then python setup.py install; \ + else python setup.py install --root "$(prefix)"; fi + install --mode=755 xend.py $(prefix)/usr/sbin + ln -sf xend.py $(prefix)/usr/sbin/xend dist: all - mkdir -p ../../../install/sbin - cp $(BIN) ../../../install/sbin - chmod 755 ../../../install/sbin/$(BIN) + mkdir -p ../../../../install/lib/python + for i in `find . -name 'xend_utils.so'` ; do \ + install --mode=755 $$i ../../../../install/lib/python/`basename $$i` ; \ + done + python -c 'import py_compile, sys; py_compile.compile("XenoUtil.py")' + install --mode=755 xend.py ../../../../install/sbin + ln -sf xend.py ../../../../install/sbin/xend clean: - $(RM) *.a *.so *.o *.rpm $(BIN) + rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm $(BIN): $(OBJS) $(CC) -o $@ $^ -L../xc/lib -lxc diff --git a/tools/xend/setup.py b/tools/xend/setup.py new file mode 100644 index 0000000000..9bc967785f --- /dev/null +++ b/tools/xend/setup.py @@ -0,0 +1,11 @@ + +from distutils.core import setup, Extension + +module = Extension("xend_utils", + include_dirs = ["../xc/lib", + "../../xenolinux-sparse/include"], + library_dirs = ["../xc/lib"], + libraries = ["xc"], + sources = ["xend_utils.c"]) + +setup(name = "xend_utils", version = "1.0", ext_modules = [module]) diff --git a/tools/xend/xend.py b/tools/xend/xend.py new file mode 100755 index 0000000000..313dc06575 --- /dev/null +++ b/tools/xend/xend.py @@ -0,0 +1,454 @@ +#!/usr/bin/env python + + +########################################################### +## xend.py -- Xen controller daemon +## Copyright (c) 2004, K A Fraser (University of Cambridge) +########################################################### + + +import errno, re, os, pwd, select, signal, socket, struct, sys, tempfile, time +import xend_utils, Xc + + + +# The following parameters could be placed in a configuration file. +PID = '/var/run/xend.pid' +LOG = '/var/log/xend.log' +USER = 'root' +CONTROL_DIR = '/var/run/xend' +UNIX_SOCK = 'management_sock' # relative to CONTROL_DIR + + + +## +## console_interface: +## Each control interface owns an instance of this class, which manages +## the current state of the console interface. Normally a console interface +## will be one of two state: +## LISTENING: listening for a connection on TCP port 'self.port' +## CONNECTED: sending/receiving console data on TCP port 'self.port' +## +## A dictionary of all active interfaces, indexed by TCP socket descriptor, +## is accessible as 'console_interface.interface_list'. +## +## NB. When a class instance is to be destroyed you *must* call the 'close' +## method. Otherwise a stale reference will eb left in the interface list. +## +class console_interface: + + # The various states that a console interface may be in. + CLOSED = 0 # No console activity + LISTENING = 1 # Listening on port 'self.port'. Socket object 'self.sock'. + CONNECTED = 2 # Active connection on 'self.port'. Socket obj 'self.sock'. + + + # Dictionary of all active (non-closed) console interfaces. + interface_list = {} + + + # NB. 'key' is an opaque value that has no meaning in this class. + def __init__(self, port, key): + self.status = console_interface.CLOSED + self.port = port + self.key = key + + + # Is this interface closed (inactive)? + def closed(self): + return self.status == console_interface.CLOSED + + + # Is this interface listening? + def listening(self): + return self.status == console_interface.LISTENING + + + # Is this interface active and connected? + def connected(self): + return self.status == console_interface.CONNECTED + + + # Close the interface, if it is not closed already. + def close(self): + if not self.closed(): + del console_interface.interface_list[self.sock.fileno()] + self.sock.close() + del self.sock + self.status = console_interface.CLOSED + + + # Move the interface into the 'listening' state. Opens a new listening + # socket and updates 'interface_list'. + def listen(self): + # Close old socket (if any), and create a fresh one. + self.close() + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + + try: + # Turn the new socket into a non-blocking listener. + self.sock.setblocking(False) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 0, 0)) + self.sock.bind(('', self.port)) + self.sock.listen(1) + + # Announce the new status of thsi interface. + self.status = console_interface.LISTENING + console_interface.interface_list[self.sock.fileno()] = self + + except: + # In case of trouble ensure we get rid of dangling socket reference + self.sock.close() + del self.sock + raise + + + # Move a listening interface into the 'connected' state. + def connect(self): + # Pick up a new connection, if one is available. + try: + (sock, addr) = self.sock.accept() + except: + return 0 + sock.setblocking(False) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 0, 0)) + + # Close the listening socket. + self.sock.close() + + # Publish the new socket and the new interface state. + self.sock = sock + self.status = console_interface.CONNECTED + console_interface.interface_list[self.sock.fileno()] = self + return 1 + + + +## +## new_control_interface: +## Create a new control interface with the specified domain 'dom'. +## The console port may also be specified; otehrwise a suitable port is +## automatically allocated. +## +def new_control_interface(dom, console_port=-1): + # Allocate an event channel. Clear pending notifications. + port = xend_utils.port(dom) + notifier.clear(port.local_port, notifier.NORMAL) + notifier.clear(port.local_port, notifier.DISCONNECT) + + # If necessary, compute a suitable TCP port for console I/O. + if console_port < 0: + console_port = 9600 + port.local_port + + # Create a listenign console interface. + con_if = console_interface(console_port, port.local_port) + con_if.listen() + + # Add control state to the master list. + control_list[port.local_port] = \ + (port, xend_utils.buffer(), xend_utils.buffer(), con_if) + + # Construct the successful response to be returned to the requester. + response = { 'success': True } + response['local_port'] = port.local_port + response['remote_port'] = port.remote_port + response['console_port'] = console_port + return response + + + +def daemon_loop(): + global control_list, notifier + + xc = Xc.new() + control_list = {} + + # Ignore writes to disconnected sockets. We clean up differently. + signal.signal(signal.SIGPIPE, signal.SIG_IGN) + + # Construct the management interface. This is a UNIX domain socket via + # which we receive 'request' datagrams. Each request is a string that + # can be eval'ed as a Python statement. Responses can be remotely eval'ed + # by the requester to create a Python dictionary of result values. + management_interface = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + if os.path.exists(CONTROL_DIR+'/'+UNIX_SOCK): + os.unlink(CONTROL_DIR+'/'+UNIX_SOCK) + management_interface.setblocking(False) + management_interface.bind(CONTROL_DIR+'/'+UNIX_SOCK) + + notifier = xend_utils.notifier() + + ## + ## MAIN LOOP + ## + while 1: + + # Construct a poll set. We wait on: + # 1. Requests on the management interface. + # 2. Incoming event-channel notifications. + # Furthermore, for each active control interface: + # 3. Incoming console data. + # 4. Space for outgoing console data (if there is data to send). + waitset = select.poll() + waitset.register(management_interface, select.POLLIN) + waitset.register(notifier, select.POLLIN) + for idx, (port, rbuf, wbuf, con_if) in control_list.items(): + if not con_if.closed(): + pflags = select.POLLIN + if not rbuf.empty() and con_if.connected(): + pflags = select.POLLIN | select.POLLOUT + waitset.register(con_if.sock.fileno(), pflags) + + # Wait for something to do... + fdset = waitset.poll() + + # Look for messages on the management interface. + # These should consist of executable Python statements that call + # well-known management functions (e.g., new_control_interface(dom=9)). + try: + data, addr = management_interface.recvfrom(2048) + except socket.error, error: + if error[0] != errno.EAGAIN: + raise + else: + if addr: + # Evaluate the request in an exception-trapping sandbox. + try: + print "Mgmt_req[%s]: %s" % (addr, data) + response = str(eval(data)) + + except: + # Catch all exceptions and turn into an error response: + # status: False + # error_type: 'exception' + # exception_type: name of exception type. + # exception value: textual exception value. + exc_type, exc_val = sys.exc_info()[:2] + response = { 'success': False } + response['error_type'] = 'exception' + response['exception_type'] = str(exc_type) + response['exception_value'] = str(exc_val) + response = str(response) + + # Try to send a response to the requester. + try: + print "Mgmt_rsp[%s]: %s" % (addr, response) + management_interface.sendto(response, addr) + except socket.error, error: + pass + + # Do work for every console interface that hit in the poll set. + for (fd, events) in fdset: + if not console_interface.interface_list.has_key(fd): + continue + con_if = console_interface.interface_list[fd] + + # If the interface is listening, check for pending connections. + if con_if.listening(): + con_if.connect() + + # All done if the interface is not connected. + if not con_if.connected(): + continue + (port, rbuf, wbuf, con_if) = control_list[con_if.key] + + # Send as much pending data as possible via the socket. + while not rbuf.empty(): + try: + bytes = con_if.sock.send(rbuf.peek()) + if bytes > 0: + rbuf.discard(bytes) + except socket.error, error: + pass + + # Read as much data as is available. Don't worry about + # overflowing our buffer: it's more important to read the + # incoming data stream and detect errors or closure of the + # remote end in a timely manner. + try: + while 1: + data = con_if.sock.recv(2048) + # Return of zero means the remote end has disconnected. + # We therefore return the console interface to listening. + if not data: + con_if.listen() + break + wbuf.write(data) + except socket.error, error: + # Assume that most errors mean that the connection is dead. + # In such cases we return the interface to 'listening' state. + if error[0] != errno.EAGAIN: + print "Better return to listening" + con_if.listen() + print "New status: " + str(con_if.status) + + # We may now have pending data to send via the relevant + # inter-domain control interface. If so then we send all we can + # and notify the remote end. + work_done = False + while not wbuf.empty() and port.space_to_write_request(): + msg = xend_utils.message(0, 0, 0) + msg.append_payload(wbuf.read(msg.MAX_PAYLOAD)) + port.write_request(msg) + work_done = True + if work_done: + port.notify() + + # Process control-interface notifications from other guest OSes. + while 1: + # Grab a notification, if there is one. + notification = notifier.read() + if not notification: + break + (idx, type) = notification + + # If we pick up a disconnect notification then we do any necessary + # cleanup, even if the event channel doesn't belong to us. + # This is intended to prevent the event-channel port space from + # getting clogged with stale connections. + if type == notifier.DISCONNECT: + ret = xc.evtchn_status(idx) + if ret['status'] != 'connected': + notifier.clear(idx, notifier.NORMAL) + notifier.clear(idx, notifier.DISCONNECT) + if control_list.has_key(idx): + (port, rbuf, wbuf, con_if) = control_list[idx] + con_if.close() + del control_list[idx], port, rbuf, wbuf, con_if + elif ret['status'] == 'disconnected': + # There's noone to do the closure for us... + xc.evtchn_close(idx) + + # A standard notification: probably means there are messages to + # read or that there is space to write messages. + elif type == notifier.NORMAL and control_list.has_key(idx): + (port, rbuf, wbuf, con_if) = control_list[idx] + work_done = False + + # We clear the notification before doing any work, to avoid + # races. + notifier.clear(idx, notifier.NORMAL) + + # Read incoming requests. Currently assume that request + # message always containb console data. + while port.request_to_read(): + msg = port.read_request() + rbuf.write(msg.get_payload()) + port.write_response(msg) + work_done = True + + # Incoming responses are currently thrown on the floor. + while port.response_to_read(): + msg = port.read_response() + work_done = True + + # Send as much pending console data as there is room for. + while not wbuf.empty() and port.space_to_write_request(): + msg = xend_utils.message(0, 0, 0) + msg.append_payload(wbuf.read(msg.MAX_PAYLOAD)) + port.write_request(msg) + work_done = True + + # Finally, notify the remote end of any work that we did. + if work_done: + port.notify() + + + +def cleanup_daemon(kill=False): + # No cleanup to do if the PID file is empty. + if not os.path.isfile(PID) or not os.path.getsize(PID): + return 0 + # Read the PID of the previous invocation and search active process list. + pid = open(PID, 'r').read() + lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines() + for line in lines: + if re.search('^ *' + pid + '.+xend', line): + if not kill: + print "Daemon is already running (PID %d)" % int(pid) + return 1 + # Old daemon is still active: terminate it. + os.kill(int(pid), 1) + # Delete the, now stale, PID file. + os.remove(PID) + return 0 + + + +def start_daemon(): + if cleanup_daemon(kill=False): + return 1 + + if not os.path.exists(CONTROL_DIR): + os.mkdir(CONTROL_DIR) + + # Open log file. Truncate it if non-empty, and request line buffering. + if os.path.isfile(LOG): + os.rename(LOG, LOG+'.old') + logfile = open(LOG, 'w+', 1) + + # Detach from TTY. + os.setsid() + + # Set the UID. + try: + os.setuid(pwd.getpwnam(USER)[2]) + except KeyError, error: + print "Error: no such user '%s'" % USER + return 1 + + # Ensure that zombie children are automatically reaped. + xend_utils.autoreap() + + # Fork -- parent writes the PID file and exits. + pid = os.fork() + if pid: + pidfile = open(PID, 'w') + pidfile.write(str(pid)) + pidfile.close() + return 0 + + # Close down standard file handles + try: + os.close(0) # stdin + os.close(1) # stdout + os.close(2) # stderr + except: + pass + + # Redirect output to log file, then enter the main loop. + sys.stdout = sys.stderr = logfile + daemon_loop() + return 0 + + + +def stop_daemon(): + return cleanup_daemon(kill=True) + + + +def main(): + xend_utils.autoreap() + if not sys.argv[1:]: + print 'usage: %s {start|stop|restart}' % sys.argv[0] + elif os.fork(): + pid, status = os.wait() + return status >> 8 + elif sys.argv[1] == 'start': + return start_daemon() + elif sys.argv[1] == 'stop': + return stop_daemon() + elif sys.argv[1] == 'restart': + return stop_daemon() or start_daemon() + else: + print 'not an option:', sys.argv[1] + return 1 + + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/xend/xend_utils.c b/tools/xend/xend_utils.c index ef6e903ddd..81b101e5c8 100644 --- a/tools/xend/xend_utils.c +++ b/tools/xend/xend_utils.c @@ -1,16 +1,16 @@ /****************************************************************************** - * xend.c - * - * The grand Xen daemon. For now it's just a virtual-console concentrator. + * xend_utils.c * * Copyright (c) 2004, K A Fraser */ +#include #include #include #include #include #include +#include #include #include #include @@ -32,64 +32,302 @@ #define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */ #define EVTCHN_RESET _IO('E', 1) /* Clear notification buffer. Clear errors. */ -/* Error macros. */ -#define ERROR(_f, _a...) \ - fprintf ( stderr, "ERROR: " _f "\n" , ## _a ); -#define SYS_ERROR(_f, _a...) \ - fprintf ( stderr, "ERROR: " _f " [errno=%d (%s)]\n" , \ - ## _a , errno , strerror(errno) ); -#define HINT(_f, _a...) \ - fprintf ( stderr, "Hint: " _f "\n" , ## _a ); -#define ROOT_HINT() HINT("You must execute this daemon as root.") -#define DOM0_HINT() HINT("You must execute this daemon " \ - "on a privileged Xenolinux instance (e.g., DOM0).") - -#if 0 -#define DPRINTF(_f, _a...) \ - fprintf ( stdout, _f "\n" , ## _a ); -#else -#define DPRINTF(_f, _a...) ((void)0) -#endif - -/* Per-port Tx/Rx buffering. */ -#define CONBUFSZ 65536 -#define MASK_CONBUF_IDX(_i) ((_i)&(CONBUFSZ-1)) - -struct portinfo; -typedef struct portinfo { - u64 dom; - control_if_t *interface; - CONTROL_RING_IDX tx_req_cons, tx_resp_prod; - CONTROL_RING_IDX rx_req_prod, rx_resp_cons; - char *tx_buf, *rx_buf; - unsigned int txp, txc, rxp, rxc; -#define CONSTAT_CLOSED 0 -#define CONSTAT_LISTENING 1 -#define CONSTAT_CONNECTED 2 - int con_fd, con_status; - struct portinfo **pprev, *next; /* links to other active ports */ -} portinfo_t; - -#define PORT(_pinfo) ((_pinfo)-portinfo) -#define TX_EMPTY(_pinfo) ((_pinfo)->txp == (_pinfo)->txc) -#define TX_FULL(_pinfo) (((_pinfo)->txp - (_pinfo)->txc) == CONBUFSZ) -#define RX_EMPTY(_pinfo) ((_pinfo)->rxp == (_pinfo)->rxc) -#define RX_FULL(_pinfo) (((_pinfo)->rxp - (_pinfo)->rxc) == CONBUFSZ) - -static portinfo_t *active_head; /* linked list of active ports */ -static portinfo_t portinfo[1024]; /* array of all ports */ -static int xc_fd, evt_fd, mem_fd; - -#define PAGE_SIZE 4096 /* size of a machine page frame */ -#define BATCH_SIZE 512 /* maximum notifications to read at a time */ - -static int make_consock_listener(portinfo_t *pinfo); -static int make_consock_connected(portinfo_t *pinfo); -static void make_consock_closed(portinfo_t *pinfo); -static void do_consock_read(portinfo_t *pinfo); -static void do_consock_write(portinfo_t *pinfo); -static int process_evtchn_reads(portinfo_t *pinfo); -static int process_evtchn_writes(portinfo_t *pinfo); +/* Size of a machine page frame. */ +#define PAGE_SIZE 4096 + + +/* + * *********************** NOTIFIER *********************** + */ + +typedef struct { + PyObject_HEAD; + int evtchn_fd; +} xu_notifier_object; + +static PyObject *xu_notifier_read(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + u16 v; + int bytes; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 ) + { + if ( errno == EINTR ) + continue; + if ( errno == EAGAIN ) + goto none; + return PyErr_SetFromErrno(PyExc_IOError); + } + + if ( bytes == sizeof(v) ) + return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK); + + none: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_clear(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + u16 v; + int idx, type; + + if ( !PyArg_ParseTuple(args, "ii", &idx, &type) ) + return NULL; + + v = (u16)idx | (u16)type; + + (void)write(xun->evtchn_fd, &v, sizeof(v)); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + return PyInt_FromLong(xun->evtchn_fd); +} + +static PyMethodDef xu_notifier_methods[] = { + { "read", + (PyCFunction)xu_notifier_read, + METH_VARARGS, + "Read a (@port, @type) pair.\n" }, + + { "clear", + (PyCFunction)xu_notifier_clear, + METH_VARARGS, + "Clear a (@port, @type) pair.\n" }, + + { "fileno", + (PyCFunction)xu_notifier_fileno, + METH_VARARGS, + "Return the file descriptor for the notification channel.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_notifier_type; + +static PyObject *xu_notifier_new(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + xun = PyObject_New(xu_notifier_object, &xu_notifier_type); + + xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR); + if ( xun->evtchn_fd == -1 ) + { + PyObject_Del((PyObject *)xun); + return PyErr_SetFromErrno(PyExc_IOError); + } + + return (PyObject *)xun; +} + +static PyObject *xu_notifier_getattr(PyObject *obj, char *name) +{ + if ( strcmp(name, "DISCONNECT") == 0 ) + return PyInt_FromLong(PORT_DISCONNECT); + if ( strcmp(name, "NORMAL") == 0 ) + return PyInt_FromLong(PORT_NORMAL); + return Py_FindMethod(xu_notifier_methods, obj, name); +} + +static void xu_notifier_dealloc(PyObject *self) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + (void)close(xun->evtchn_fd); + PyObject_Del(self); +} + +static PyTypeObject xu_notifier_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "notifier", + sizeof(xu_notifier_object), + 0, + xu_notifier_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_notifier_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** MESSAGE *********************** + */ + +typedef struct { + PyObject_HEAD; + control_msg_t msg; +} xu_message_object; + +static PyObject *xu_message_append_payload(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + char *str; + int len; + + if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) + return NULL; + + if ( (len + xum->msg.length) > sizeof(xum->msg.msg) ) + { + PyErr_SetString(PyExc_RuntimeError, "out of space in control message"); + return NULL; + } + + memcpy(&xum->msg.msg[xum->msg.length], str, len); + xum->msg.length += len; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length); +} + +static PyObject *xu_message_set_header(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + xu_message_object *xum = (xu_message_object *)self; + int type = -1, subtype = -1, id = -1; + + static char *kwd_list[] = { "type", "subtype", "id", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iii", kwd_list, + &type, &subtype, &id) ) + return NULL; + + if ( type != -1 ) + xum->msg.type = (u8)type; + if ( subtype != -1 ) + xum->msg.subtype = (u8)subtype; + if ( id != -1 ) + xum->msg.id = (u8)id; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_message_get_header(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + return Py_BuildValue("{s:i,s:i,s:i}", + "type", xum->msg.type, + "subtype", xum->msg.subtype, + "id", xum->msg.id); +} + +static PyMethodDef xu_message_methods[] = { + { "append_payload", + (PyCFunction)xu_message_append_payload, + METH_VARARGS, + "Append @str to the message payload.\n" }, + + { "get_payload", + (PyCFunction)xu_message_get_payload, + METH_VARARGS, + "Return the message payload in string form.\n" }, + + { "set_header", + (PyCFunction)xu_message_set_header, + METH_VARARGS | METH_KEYWORDS, + "Accepts keywords @type, @subtype, and @id.\n" }, + + { "get_header", + (PyCFunction)xu_message_get_header, + METH_VARARGS, + "Returns a dictionary of values for @type, @subtype, and @id.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_message_type; + +static PyObject *xu_message_new(PyObject *self, PyObject *args) +{ + xu_message_object *xum; + int type, subtype, id; + + if ( !PyArg_ParseTuple(args, "iii", &type, &subtype, &id) ) + return NULL; + + xum = PyObject_New(xu_message_object, &xu_message_type); + + xum->msg.type = type; + xum->msg.subtype = subtype; + xum->msg.id = id; + xum->msg.length = 0; + + return (PyObject *)xum; +} + +static PyObject *xu_message_getattr(PyObject *obj, char *name) +{ + xu_message_object *xum; + if ( strcmp(name, "MAX_PAYLOAD") == 0 ) + return PyInt_FromLong(sizeof(xum->msg.msg)); + return Py_FindMethod(xu_message_methods, obj, name); +} + +static void xu_message_dealloc(PyObject *self) +{ + PyObject_Del(self); +} + +static PyTypeObject xu_message_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "message", + sizeof(xu_message_object), + 0, + xu_message_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_message_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** PORT *********************** + */ static control_if_t *map_control_interface(int fd, unsigned long pfn) { @@ -99,518 +337,670 @@ static control_if_t *map_control_interface(int fd, unsigned long pfn) return NULL; return (control_if_t *)(vaddr + 2048); } - static void unmap_control_interface(int fd, control_if_t *c) { char *vaddr = (char *)c - 2048; (void)munmap(vaddr, PAGE_SIZE); } -/* Returns TRUE if the channel is open on exit. */ -static int handle_channel_exception(unsigned int port) +typedef struct { + PyObject_HEAD; + int mem_fd; + int xc_handle; + u64 remote_dom; + int local_port, remote_port; + control_if_t *interface; + CONTROL_RING_IDX tx_req_cons, tx_resp_prod; + CONTROL_RING_IDX rx_req_prod, rx_resp_cons; +} xu_port_object; + +static PyObject *port_error; + +static PyObject *xu_port_notify(PyObject *self, PyObject *args) { - xc_dominfo_t info; - unsigned int remote_port, status; - u64 remote_dom; - u16 wbuf; - portinfo_t *pinfo = &portinfo[port]; + xu_port_object *xup = (xu_port_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + (void)xc_evtchn_send(xup->xc_handle, xup->local_port); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_read_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX c = xup->tx_req_cons; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - if ( xc_evtchn_status(xc_fd, DOMID_SELF, port, - &remote_dom, &remote_port, &status) != 0 ) + if ( (c == cif->tx_req_prod) || + ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) { - SYS_ERROR("Unexpected failure when obtaining port-%d status.", port); - exit(1); + PyErr_SetString(port_error, "no request to read"); + return NULL; } - - if ( status != EVTCHNSTAT_connected ) + + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; + xum = PyObject_New(xu_message_object, &xu_message_type); + memcpy(&xum->msg, cmsg, sizeof(*cmsg)); + if ( xum->msg.length > sizeof(xum->msg.msg) ) + xum->msg.length = sizeof(xum->msg.msg); + xup->tx_req_cons++; + return (PyObject *)xum; +} + +static PyObject *xu_port_write_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX p = xup->rx_req_prod; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) + return NULL; + + if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) { - DPRINTF("Port %d not connected: cleaning up.", port); - if ( pinfo->interface != NULL ) - { - unmap_control_interface(mem_fd, pinfo->interface); - pinfo->interface = NULL; - *(pinfo->pprev) = pinfo->next; - if ( pinfo->next != NULL ) - pinfo->next->pprev = pinfo->pprev; - make_consock_closed(pinfo); - free(pinfo->tx_buf); - free(pinfo->rx_buf); - memset(pinfo, 0, sizeof(*pinfo)); - } - /* Cleanup sanity: we'll be the grim reaper. */ - wbuf = port | PORT_NORMAL; - (void)write(evt_fd, &wbuf, sizeof(wbuf)); - wbuf = port | PORT_DISCONNECT; - (void)write(evt_fd, &wbuf, sizeof(wbuf)); - if ( status == EVTCHNSTAT_disconnected ) - (void)xc_evtchn_close(xc_fd, DOMID_SELF, port); - return 0; + PyErr_SetString(PyExc_TypeError, "expected a xend_utils.message"); + return NULL; } - /* We only deal with initial ports (id == 0). */ - if ( remote_port != 0 ) - return 0; - - if ( pinfo->interface == NULL ) + if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) { - DPRINTF("New control interface for DOM%llu on port %d.", - remote_dom, port); - if ( xc_domain_getinfo(xc_fd, remote_dom, 1, &info) != 1 ) - { - SYS_ERROR("Failed to obtain DOM%llu status.", remote_dom); - exit(1); - } - memset(pinfo, 0, sizeof(*pinfo)); - pinfo->interface = - map_control_interface(mem_fd, info.shared_info_frame); - pinfo->tx_buf = malloc(CONBUFSZ); - pinfo->rx_buf = malloc(CONBUFSZ); - pinfo->dom = remote_dom; - pinfo->con_status = CONSTAT_CLOSED; - if ( !make_consock_listener(pinfo) ) - { - ERROR("Could not start console %d in listener status.", - PORT(pinfo)); - exit(1); - } - pinfo->pprev = &active_head; - if ( (pinfo->next = active_head) != NULL ) - pinfo->next->pprev = &pinfo->next; - active_head = pinfo; + PyErr_SetString(port_error, "no space to write request"); + return NULL; } - return 1; + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; + memcpy(cmsg, &xum->msg, sizeof(*cmsg)); + + xup->rx_req_prod = cif->rx_req_prod = p + 1; + + Py_INCREF(Py_None); + return Py_None; } -static void process_channel(unsigned int port) +static PyObject *xu_port_read_response(PyObject *self, PyObject *args) { - portinfo_t *pinfo = &portinfo[port]; - u16 wbuf = port; + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX c = xup->rx_resp_cons; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; - /* Acknowledge the notification. */ - (void)write(evt_fd, &wbuf, sizeof(wbuf)); + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - /* Process requests; send notification if we updated either ring. */ - if ( process_evtchn_reads(pinfo) || process_evtchn_writes(pinfo) ) - (void)xc_evtchn_send(xc_fd, port); + if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) + { + PyErr_SetString(port_error, "no response to read"); + return NULL; + } + + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)]; + xum = PyObject_New(xu_message_object, &xu_message_type); + memcpy(&xum->msg, cmsg, sizeof(*cmsg)); + if ( xum->msg.length > sizeof(xum->msg.msg) ) + xum->msg.length = sizeof(xum->msg.msg); + xup->rx_resp_cons++; + return (PyObject *)xum; } -int main(int argc, char **argv) +static PyObject *xu_port_write_response(PyObject *self, PyObject *args) { - struct pollfd polls[1025]; /* one per port, plus /dev/xeno/evtchn */ - portinfo_t *pinfo; - unsigned int batch, bytes, i, port, fd_idx; - u16 buf[BATCH_SIZE]; + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX p = xup->tx_resp_prod; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; - /* Ignore writes to disconnected sockets. We clear up later. */ - (void)signal(SIGPIPE, SIG_IGN); - - if ( (evt_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR)) == -1 ) - { - SYS_ERROR("Could not open '%s'", EVTCHN_DEV_NAME); - ROOT_HINT(); - HINT("On a non-devfs system you must run 'mknod %s c %d %d'.", - EVTCHN_DEV_NAME, EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR); - exit(1); - } + if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) + return NULL; - if ( (mem_fd = open("/dev/mem", O_RDWR)) == -1 ) + if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) { - SYS_ERROR("Could not open '/dev/mem'"); - ROOT_HINT(); - exit(1); + PyErr_SetString(PyExc_TypeError, "expected a xend_utils.message"); + return NULL; } - if ( (xc_fd = xc_interface_open()) == -1 ) + if ( p == xup->tx_req_cons ) { - SYS_ERROR("Could not open Xen control interface"); - ROOT_HINT(); - DOM0_HINT(); - exit(1); + PyErr_SetString(port_error, "no space to write response"); + return NULL; } - for ( ; ; ) - { - polls[0].fd = evt_fd; - polls[0].events = POLLIN; + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)]; + memcpy(cmsg, &xum->msg, sizeof(*cmsg)); - fd_idx = 1; - for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next ) - { - switch ( pinfo->con_status ) - { - case CONSTAT_LISTENING: - polls[fd_idx].fd = pinfo->con_fd; - polls[fd_idx].events = POLLIN; - fd_idx++; - break; - case CONSTAT_CONNECTED: - polls[fd_idx].fd = pinfo->con_fd; - polls[fd_idx].events = POLLIN | (RX_EMPTY(pinfo)?0:POLLOUT); - fd_idx++; - break; - } - } + xup->tx_resp_prod = cif->tx_resp_prod = p + 1; - while ( poll(polls, fd_idx, -1) == -1 ) - { - if ( errno == EINTR ) - continue; - SYS_ERROR("Unexpected error from poll()."); - exit(1); - } + Py_INCREF(Py_None); + return Py_None; +} - fd_idx = 1; - for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next ) - { - switch ( pinfo->con_status ) - { - case CONSTAT_LISTENING: - if ( ((polls[fd_idx].revents & POLLIN) != 0) ) - (void)make_consock_connected(pinfo); - break; - case CONSTAT_CONNECTED: - if ( ((polls[fd_idx].revents & POLLOUT) != 0) ) - do_consock_write(pinfo); - if ( ((polls[fd_idx].revents & POLLIN) != 0) ) - do_consock_read(pinfo); - break; - } - fd_idx++; - } +static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX c = xup->tx_req_cons; + control_if_t *cif = xup->interface; - while ( (bytes = read(evt_fd, buf, sizeof(buf))) == -1 ) - { - if ( errno == EINTR ) - continue; - if ( errno == EAGAIN ) - { - bytes = 0; - break; - } - SYS_ERROR("Unexpected error while reading '%s'.", EVTCHN_DEV_NAME); - exit(1); - } - - if ( bytes == 0 ) - continue; + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - if ( (bytes & 1) != 0 ) - { - ERROR("Bad read length (%d bytes) from '%s'.", - bytes, EVTCHN_DEV_NAME); - exit(1); - } - - batch = bytes / sizeof(u16); - for ( i = 0; i < batch; i++ ) - { - port = buf[i] & PORTIDX_MASK; - - if ( buf[i] & PORT_DISCONNECT ) - { - DPRINTF("Disconnect on port %d.", port); - (void)handle_channel_exception(port); - continue; - } - - if ( portinfo[port].interface == NULL ) - { - DPRINTF("Unexpected notification on port %d.", port); - if ( !handle_channel_exception(port) ) - continue; - } - - process_channel(port); - } - } + if ( (c == cif->tx_req_prod) || + ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX p = xup->rx_req_prod; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - (void)xc_interface_close(xc_fd); - (void)close(mem_fd); - (void)close(evt_fd); + if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) + return PyInt_FromLong(0); - return 0; + return PyInt_FromLong(1); } +static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX c = xup->rx_resp_cons; + control_if_t *cif = xup->interface; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) + return PyInt_FromLong(0); -/* Returns non-zero if console is listening on exit. */ -static int make_consock_listener(portinfo_t *pinfo) + return PyInt_FromLong(1); +} + +static PyObject *xu_port_space_to_write_response( + PyObject *self, PyObject *args) { - int reuseaddr_flag = 1; - struct linger linger; - int tcp_port = 9600 + PORT(pinfo); - int fd, flags; - struct sockaddr_in sa; + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX p = xup->tx_resp_prod; - if ( pinfo->con_status == CONSTAT_LISTENING ) - return 1; + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - if ( pinfo->con_status == CONSTAT_CONNECTED ) - { - (void)close(pinfo->con_fd); - pinfo->con_status = CONSTAT_CLOSED; - } + if ( p == xup->tx_req_cons ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyMethodDef xu_port_methods[] = { + { "notify", + (PyCFunction)xu_port_notify, + METH_VARARGS, + "Send a notification to the remote end.\n" }, + + { "read_request", + (PyCFunction)xu_port_read_request, + METH_VARARGS, + "Read a request message from the control interface.\n" }, + + { "write_request", + (PyCFunction)xu_port_write_request, + METH_VARARGS, + "Write a request message to the control interface.\n" }, + + { "read_response", + (PyCFunction)xu_port_read_response, + METH_VARARGS, + "Read a response message from the control interface.\n" }, + + { "write_response", + (PyCFunction)xu_port_write_response, + METH_VARARGS, + "Write a response message to the control interface.\n" }, + + { "request_to_read", + (PyCFunction)xu_port_request_to_read, + METH_VARARGS, + "Returns TRUE if there is a request message to read.\n" }, + + { "space_to_write_request", + (PyCFunction)xu_port_space_to_write_request, + METH_VARARGS, + "Returns TRUE if there is space to write a request message.\n" }, + + { "response_to_read", + (PyCFunction)xu_port_response_to_read, + METH_VARARGS, + "Returns TRUE if there is a response message to read.\n" }, + + { "space_to_write_response", + (PyCFunction)xu_port_space_to_write_response, + METH_VARARGS, + "Returns TRUE if there is space to write a response message.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_port_type; + +static PyObject *xu_port_new(PyObject *self, PyObject *args) +{ + xu_port_object *xup; + u64 dom; + int port1, port2; + xc_dominfo_t info; + + if ( !PyArg_ParseTuple(args, "L", &dom) ) + return NULL; + + xup = PyObject_New(xu_port_object, &xu_port_type); - if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) + if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 ) { - SYS_ERROR("Could not create TCP socket."); - return 0; + PyErr_SetString(port_error, "Could not open '/dev/mem'"); + goto fail1; } - linger.l_onoff = 0; - if ( (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - &reuseaddr_flag, sizeof(int)) != 0) || - (setsockopt(fd, SOL_SOCKET, SO_LINGER, - &linger, sizeof(linger)) != 0) ) + if ( (xup->xc_handle = xc_interface_open()) == -1 ) { - SYS_ERROR("Could not enable immediate reuse of socket port."); - close(fd); - return 0; + PyErr_SetString(port_error, "Could not open Xen control interface"); + goto fail2; } - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(INADDR_ANY); - sa.sin_port = htons(tcp_port); - if ( bind(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0 ) + if ( xc_evtchn_open(xup->xc_handle, DOMID_SELF, dom, &port1, &port2) != 0 ) { - SYS_ERROR("Unable to bind to console port %d.", tcp_port); - close(fd); - return 0; + PyErr_SetString(port_error, "Could not open channel to domain"); + goto fail3; } - if ( listen(fd, 5) != 0 ) + if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) || + (info.domid != dom) ) { - SYS_ERROR("Unable to listen on console port %d.", tcp_port); - close(fd); - return 0; + PyErr_SetString(port_error, "Failed to obtain domain status"); + goto fail4; } - if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) || - (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) ) + xup->interface = + map_control_interface(xup->mem_fd, info.shared_info_frame); + if ( xup->interface == NULL ) { - SYS_ERROR("Unable to set non-blocking status for console listener."); - close(fd); - return 0; + PyErr_SetString(port_error, "Failed to map domain control interface"); + goto fail4; } - pinfo->con_fd = fd; - pinfo->con_status = CONSTAT_LISTENING; - return 1; + xup->tx_req_cons = 0; + xup->tx_resp_prod = 0; + xup->rx_req_prod = 0; + xup->rx_resp_cons = 0; + xup->remote_dom = dom; + xup->local_port = port1; + xup->remote_port = port2; + + return (PyObject *)xup; + + + fail4: + (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1); + fail3: + (void)xc_interface_close(xup->xc_handle); + fail2: + (void)close(xup->mem_fd); + fail1: + PyObject_Del((PyObject *)xup); + return NULL; } -/* Returns non-zero if console is connected on exit. */ -static int make_consock_connected(portinfo_t *pinfo) +static PyObject *xu_port_getattr(PyObject *obj, char *name) { - int fd, flags, sa_len; - struct linger linger; - struct sockaddr_in sa; + xu_port_object *xup = (xu_port_object *)obj; + if ( strcmp(name, "local_port") == 0 ) + return PyInt_FromLong(xup->local_port); + if ( strcmp(name, "remote_port") == 0 ) + return PyInt_FromLong(xup->remote_port); + if ( strcmp(name, "remote_dom") == 0 ) + return PyLong_FromUnsignedLongLong(xup->remote_dom); + return Py_FindMethod(xu_port_methods, obj, name); +} - if ( pinfo->con_status == CONSTAT_CONNECTED ) - return 1; +static void xu_port_dealloc(PyObject *self) +{ + xu_port_object *xup = (xu_port_object *)self; + unmap_control_interface(xup->mem_fd, xup->interface); + (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port); + (void)xc_interface_close(xup->xc_handle); + (void)close(xup->mem_fd); + PyObject_Del(self); +} - if ( pinfo->con_status == CONSTAT_CLOSED ) - return 0; +static PyTypeObject xu_port_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "port", + sizeof(xu_port_object), + 0, + xu_port_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_port_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** BUFFER *********************** + */ - if ( (fd = accept(pinfo->con_fd, (struct sockaddr *)&sa, &sa_len)) == -1 ) - return 0; +#define BUFSZ 65536 +#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1)) +typedef unsigned int BUF_IDX; - linger.l_onoff = 0; - if ( setsockopt(fd, SOL_SOCKET, SO_LINGER, - &linger, sizeof(linger)) != 0 ) - { - SYS_ERROR("Could not enable immediate socket death."); - close(fd); - return 0; - } +typedef struct { + PyObject_HEAD; + char *buf; + unsigned int prod, cons; +} xu_buffer_object; - if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) || - (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) ) +static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max) +{ + PyObject *str1, *str2; + int len1, len2, c = MASK_BUF_IDX(xub->cons); + + len1 = xub->prod - xub->cons; + if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */ + len1 = BUFSZ - c; + if ( len1 > max ) /* clip to specified maximum */ + len1 = max; + if ( len1 < 0 ) /* sanity */ + len1 = 0; + + if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL ) + return NULL; + + if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) ) { - SYS_ERROR("Unable to set non-blocking status on socket."); - close(fd); - return 0; + len2 = max - len1; + if ( len2 > MASK_BUF_IDX(xub->prod) ) + len2 = MASK_BUF_IDX(xub->prod); + if ( len2 > 0 ) + { + str2 = PyString_FromStringAndSize(&xub->buf[0], len2); + if ( str2 == NULL ) + return NULL; + PyString_ConcatAndDel(&str1, str2); + if ( str1 == NULL ) + return NULL; + } } - (void)close(pinfo->con_fd); - - pinfo->con_fd = fd; - pinfo->con_status = CONSTAT_CONNECTED; - return 1; + return str1; } +static PyObject *xu_buffer_peek(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + int max = 1024; -static void make_consock_closed(portinfo_t *pinfo) + if ( !PyArg_ParseTuple(args, "|i", &max) ) + return NULL; + + return __xu_buffer_peek(xub, max); +} + +static PyObject *xu_buffer_read(PyObject *self, PyObject *args) { - if ( pinfo->con_status != CONSTAT_CLOSED ) - (void)close(pinfo->con_fd); - pinfo->con_status = CONSTAT_CLOSED; + xu_buffer_object *xub = (xu_buffer_object *)self; + PyObject *str; + int max = 1024; + + if ( !PyArg_ParseTuple(args, "|i", &max) ) + return NULL; + + if ( (str = __xu_buffer_peek(xub, max)) != NULL ) + xub->cons += PyString_Size(str); + + return str; } +static PyObject *xu_buffer_discard(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + int max, len; + + if ( !PyArg_ParseTuple(args, "i", &max) ) + return NULL; + + len = xub->prod - xub->cons; + if ( len > max ) + len = max; + if ( len < 0 ) + len = 0; + + xub->cons += len; + + return PyInt_FromLong(len); +} -static void do_consock_read(portinfo_t *pinfo) +static PyObject *xu_buffer_write(PyObject *self, PyObject *args) { - char buf[1024]; - int idx, bytes, rc, was_empty = TX_EMPTY(pinfo); + xu_buffer_object *xub = (xu_buffer_object *)self; + char *str; + int len, len1, len2; - while ( (rc = read(pinfo->con_fd, &buf, sizeof(buf))) > 0 ) - { - idx = 0; - while ( (rc != 0) && !TX_FULL(pinfo) ) - { - bytes = rc; - /* Clip copy to ring-buffer wrap. */ - if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp)) ) - bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp); - /* Clip copy to ring-buffer overflow. */ - if ( bytes > (CONBUFSZ - (pinfo->txp - pinfo->txc)) ) - bytes = CONBUFSZ - (pinfo->txp - pinfo->txc); - memcpy(&pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txp)], - &buf[idx], bytes); - pinfo->txp += bytes; - idx += bytes; - rc -= bytes; - } - } + if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) + return NULL; + + len1 = len; + if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) + len1 = BUFSZ - MASK_BUF_IDX(xub->prod); + if ( len1 > (BUFSZ - (xub->prod - xub->cons)) ) + len1 = BUFSZ - (xub->prod - xub->cons); + + if ( len1 == 0 ) + return PyInt_FromLong(0); - if ( (rc == 0) || (errno != EAGAIN) ) + memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1); + xub->prod += len1; + + if ( len1 < len ) { - DPRINTF("Console client has disconnected."); - if ( !make_consock_listener(pinfo) ) + len2 = len - len1; + if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) + len2 = BUFSZ - MASK_BUF_IDX(xub->prod); + if ( len2 > (BUFSZ - (xub->prod - xub->cons)) ) + len2 = BUFSZ - (xub->prod - xub->cons); + if ( len2 != 0 ) { - ERROR("Could not revert console %d to listener status.", - PORT(pinfo)); - exit(1); + memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2); + xub->prod += len2; + return PyInt_FromLong(len1 + len2); } } - if ( was_empty && !TX_EMPTY(pinfo) ) - { - /* There is now data to transmit to guest. Kickstart the pipeline. */ - if ( process_evtchn_writes(pinfo) ) - (void)xc_evtchn_send(xc_fd, PORT(pinfo)); - } + return PyInt_FromLong(len1); } -static void do_consock_write(portinfo_t *pinfo) +static PyObject *xu_buffer_empty(PyObject *self, PyObject *args) { - int bytes, rc; + xu_buffer_object *xub = (xu_buffer_object *)self; - while ( !RX_EMPTY(pinfo) ) - { - /* Clip transfer to ring-buffer wrap. */ - bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxc); - /* Clip transfer to ring-buffer overflow. */ - if ( bytes > (pinfo->rxp - pinfo->rxc) ) - bytes = pinfo->rxp - pinfo->rxc; - rc = write(pinfo->con_fd, - &pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxc)], - bytes); - if ( rc <= 0 ) - return; /* Nothing to do. Errors cleaned up in reader code. */ - pinfo->rxc += rc; - } + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xub->cons == xub->prod ) + return PyInt_FromLong(1); + + return PyInt_FromLong(0); } -static int process_evtchn_reads(portinfo_t *pinfo) +static PyObject *xu_buffer_full(PyObject *self, PyObject *args) { - CONTROL_RING_IDX c; - control_if_t *cif = pinfo->interface; - control_msg_t *cmsg; - unsigned int clen, idx, len, bytes; + xu_buffer_object *xub = (xu_buffer_object *)self; - for ( c = pinfo->tx_req_cons; - (c != cif->tx_req_prod) && - ((c-pinfo->tx_resp_prod) != CONTROL_RING_SIZE); - c++ ) - { - cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - if ( (clen = cmsg->length) > sizeof(cmsg->msg) ) - clen = sizeof(cmsg->msg); + if ( (xub->prod - xub->cons) == BUFSZ ) + return PyInt_FromLong(1); - if ( (cmsg->cmd_type == CMD_CONSOLE) && - (cmsg->cmd_subtype == CMD_CONSOLE_DATA) ) - { - idx = 0; - len = cmsg->length; - while ( (len != 0) && !RX_FULL(pinfo) ) - { - bytes = len; - /* Clip copy to ring-buffer wrap. */ - if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp)) ) - bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp); - /* Clip copy to ring-buffer overflow. */ - if ( bytes > (CONBUFSZ - (pinfo->rxp - pinfo->rxc)) ) - bytes = CONBUFSZ - (pinfo->rxp - pinfo->rxc); - memcpy(&pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxp)], - &cmsg->msg[idx], bytes); - pinfo->rxp += bytes; - idx += bytes; - len -= bytes; - } - } + return PyInt_FromLong(0); +} - /* Prepare response. No payload; msg type and id same as request. */ - cmsg->length = 0; - } +static PyMethodDef xu_buffer_methods[] = { + { "peek", + (PyCFunction)xu_buffer_peek, + METH_VARARGS, + "Peek up to @max bytes from the buffer. Returns a string.\n" }, - if ( c != pinfo->tx_req_cons ) + { "read", + (PyCFunction)xu_buffer_read, + METH_VARARGS, + "Read up to @max bytes from the buffer. Returns a string.\n" }, + + { "discard", + (PyCFunction)xu_buffer_discard, + METH_VARARGS, + "Discard up to @max bytes from the buffer. Returns number of bytes.\n" }, + + { "write", + (PyCFunction)xu_buffer_write, + METH_VARARGS, + "Write @string into buffer. Return number of bytes written.\n" }, + + { "empty", + (PyCFunction)xu_buffer_empty, + METH_VARARGS, + "Return TRUE if the buffer is empty.\n" }, + + { "full", + (PyCFunction)xu_buffer_full, + METH_VARARGS, + "Return TRUE if the buffer is full.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_buffer_type; + +static PyObject *xu_buffer_new(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + xub = PyObject_New(xu_buffer_object, &xu_buffer_type); + + if ( (xub->buf = malloc(BUFSZ)) == NULL ) { - /* Update private indexes. */ - pinfo->tx_resp_prod = c; - pinfo->tx_req_cons = c; - /* Queue responses and send a notification to the guest OS. */ - cif->tx_resp_prod = c; - return 1; + PyObject_Del((PyObject *)xub); + return NULL; } - return 0; + xub->prod = xub->cons = 0; + + return (PyObject *)xub; +} + +static PyObject *xu_buffer_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(xu_buffer_methods, obj, name); +} + +static void xu_buffer_dealloc(PyObject *self) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + free(xub->buf); + PyObject_Del(self); } -static int process_evtchn_writes(portinfo_t *pinfo) +static PyTypeObject xu_buffer_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "buffer", + sizeof(xu_buffer_object), + 0, + xu_buffer_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_buffer_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** MODULE WRAPPER *********************** + */ + +static void handle_child_death(int dummy) { - CONTROL_RING_IDX p, rx_resp_prod; - control_if_t *cif = pinfo->interface; - control_msg_t *cmsg; - unsigned int bytes; + while ( waitpid(-1, NULL, WNOHANG) > 0 ) + continue; +} - /* Validate the rx-response producer, an dupdate our consumer if okay. */ - rx_resp_prod = cif->rx_resp_prod; - if ( (pinfo->rx_resp_cons != rx_resp_prod) && - ((pinfo->rx_req_prod - rx_resp_prod) <= CONTROL_RING_SIZE) && - ((rx_resp_prod - pinfo->rx_resp_cons) <= CONTROL_RING_SIZE) ) - pinfo->rx_resp_cons = cif->rx_resp_prod; +static PyObject *xu_autoreap(PyObject *self, PyObject *args) +{ + struct sigaction sa; - for ( p = pinfo->rx_req_prod; - (p-pinfo->rx_resp_cons) != CONTROL_RING_SIZE; - p++ ) - { - if ( TX_EMPTY(pinfo) ) - break; - cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; - bytes = sizeof(cmsg->msg); - /* Clip transfer to ring-buffer wrap. */ - if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc)) ) - bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc); - /* Clip transfer to ring-buffer overflow. */ - if ( bytes > (pinfo->txp - pinfo->txc) ) - bytes = pinfo->txp - pinfo->txc; - cmsg->cmd_type = CMD_CONSOLE; - cmsg->cmd_subtype = CMD_CONSOLE_DATA; - cmsg->id = 0xaa; - cmsg->length = bytes; - memcpy(&cmsg->msg[0], - &pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txc)], - bytes); - pinfo->txc += bytes; - } + if ( !PyArg_ParseTuple(args, "") ) + return NULL; - if ( p != pinfo->rx_req_prod ) - { - pinfo->rx_req_prod = p; - cif->rx_req_prod = p; - return 1; - } + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handle_child_death; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + (void)sigaction(SIGCHLD, &sa, NULL); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef xu_methods[] = { + { "notifier", xu_notifier_new, METH_VARARGS, + "Create a new notifier." }, + { "message", xu_message_new, METH_VARARGS, + "Create a new communications message." }, + { "port", xu_port_new, METH_VARARGS, + "Create a new communications port." }, + { "buffer", xu_buffer_new, METH_VARARGS, + "Create a new ring buffer." }, + { "autoreap", xu_autoreap, METH_VARARGS, + "Ensure that zombie children are automatically reaped by the OS." }, + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC initxend_utils(void) +{ + PyObject *m, *d; + + m = Py_InitModule("xend_utils", xu_methods); - return 0; + d = PyModule_GetDict(m); + port_error = PyErr_NewException("xend_utils.PortError", NULL, NULL); + PyDict_SetItemString(d, "PortError", port_error); } diff --git a/tools/xentrace/Makefile b/tools/xentrace/Makefile index 2e85fcbe1a..11beb34cd6 100644 --- a/tools/xentrace/Makefile +++ b/tools/xentrace/Makefile @@ -14,18 +14,22 @@ MAN8 = $(wildcard *.8) all: $(BIN) install: all - mkdir -p /usr/bin - cp $(BIN) /usr/bin - for i in $(BIN); do chmod 755 /usr/bin/$$i; done - for i in $(MAN1); do cp $$i /usr/man/man1/$$i; done - for i in $(MAN8); do cp $$i /usr/man/man8/$$i; done + mkdir -p $(prefix)/usr/bin + mkdir -p $(prefix)/usr/man/man1 + mkdir -p $(prefix)/usr/man/man8 + cp $(BIN) $(prefix)/usr/bin + for i in $(BIN); do chmod 755 $(prefix)/usr/bin/$$i; done + for i in $(MAN1); do cp $$i $(prefix)/usr/man/man1/$$i; done + for i in $(MAN8); do cp $$i $(prefix)/usr/man/man8/$$i; done dist: all mkdir -p ../../../install/bin + mkdir -p ../../../install/man/man1 + mkdir -p ../../../install/man/man8 cp $(BIN) ../../../install/bin - chmod 755 ../../../install/bin/$(BIN) - cp $(SCRIPTS) ../../../install/bin - for i in $(SCRIPTS); do chmod 755 ../../../install/bin/$i; done + for i in $(BIN); do chmod 755 ../../../install/bin/$$i; done + for i in $(MAN1); do cp $$i ../../../install/man/man1/$$i; done + for i in $(MAN8); do cp $$i ../../../install/man/man8/$$i; done clean: $(RM) *.a *.so *.o *.rpm $(BIN) diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c index 367b9b4f0e..4d42d8d9da 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c @@ -52,9 +52,9 @@ static void nonpriv_conwrite(const char *s, unsigned int count) p = MASK_CONTROL_IDX(ctrl_if->tx_req_prod); - ctrl_if->tx_ring[p].cmd_type = CMD_CONSOLE; - ctrl_if->tx_ring[p].cmd_subtype = CMD_CONSOLE_DATA; - ctrl_if->tx_ring[p].id = 0xaa; + ctrl_if->tx_ring[p].type = CMSG_CONSOLE; + ctrl_if->tx_ring[p].subtype = CMSG_CONSOLE_DATA; + ctrl_if->tx_ring[p].id = 0xaa; src = dst = 0; while ( (src < count) && (dst < (sizeof(ctrl_if->tx_ring[p].msg)-1)) ) { @@ -202,8 +202,8 @@ static void __do_console_io(void) for ( c = ctrl_if->rx_resp_prod; c != ctrl_if->rx_req_prod; c++ ) { msg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(c)]; - if ( (msg->cmd_type == CMD_CONSOLE) && - (msg->cmd_subtype == CMD_CONSOLE_DATA) ) + if ( (msg->type == CMSG_CONSOLE) && + (msg->subtype == CMSG_CONSOLE_DATA) ) { for ( i = 0; i < msg->length; i++ ) tty_insert_flip_char(xeno_console_tty, msg->msg[i], 0); @@ -225,9 +225,9 @@ static void __do_console_io(void) if ( (wc == wp) && (x_char == 0) ) break; msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(c)]; - msg->cmd_type = CMD_CONSOLE; - msg->cmd_subtype = CMD_CONSOLE_DATA; - msg->id = 0xaa; + msg->type = CMSG_CONSOLE; + msg->subtype = CMSG_CONSOLE_DATA; + msg->id = 0xaa; len = 0; if ( x_char != 0 ) /* Handle XON/XOFF urgently. */ { diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h b/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h index aa8375e729..dd15a96bff 100644 --- a/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h +++ b/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h @@ -8,11 +8,11 @@ #define __CONTROL_IF_H__ typedef struct { - u8 cmd_type; /* echoed in response */ - u8 cmd_subtype; /* echoed in response */ - u8 id; /* echoed in response */ - u8 length; /* number of bytes in 'msg' */ - unsigned char msg[60]; /* command-specific message data */ + u8 type; /* echoed in response */ + u8 subtype; /* echoed in response */ + u8 id; /* echoed in response */ + u8 length; /* number of bytes in 'msg' */ + unsigned char msg[60]; /* type-specific message data */ } control_msg_t; #define CONTROL_RING_SIZE 8 @@ -26,7 +26,7 @@ typedef struct { CONTROL_RING_IDX rx_req_prod, rx_resp_prod; } control_if_t; -#define CMD_CONSOLE 0 -#define CMD_CONSOLE_DATA 0 +#define CMSG_CONSOLE 0 +#define CMSG_CONSOLE_DATA 0 #endif /* __CONTROL_IF_H__ */ -- 2.30.2